/**
 * Copyright (c) 2008, Keisuke Inoue, Syracuse Unviersity
 * All rights reserved.
 *
 */
package edu.syr.iis.web.model;

import java.util.List;
import edu.syr.iis.web.util.HibernateUtil;

import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;

/**
 * Manages database operations for Conversation table
 * @author kinoue
 *
 */
public class ConversationManager
{
	/**
	 * Returns list of all conversations in a specified dataset
	 *  ordered by conversationId
	 */


	/**
	 * Returns list of all Conversation database records sorted by conversationId
	 */
	public List<Conversation> getConversations(Dataset dataset)
	{
		return getConversations(dataset, true);
	}

	public List<Conversation> getConversations(Dataset dataset, boolean lazy)
	{
		List<Conversation> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{				
			list  = session.createQuery("FROM Conversation " + 
			" WHERE datasetId = ?").setInteger(0, dataset.datasetId).list();
			for (Conversation conversation: list )
			{
				Hibernate.initialize(conversation.getMessages());
				Hibernate.initialize(conversation.getAnnotators());
				// conversation.getAnnotators().size();							
				for (User annotator: conversation.getAnnotators())
				{
					Hibernate.initialize(annotator);
					// System.out.println("Checking out the annotator: " + annotator.userName);
				}							
				//conversation.getMessages().size();
			}
			
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}



	/**
	 * Returns list of all Conversation database records sorted by conversationId
	 */
	public List<Conversation> getConversations(int datasetId)
	{
		return getConversations(datasetId, true);
	}

	public List<Conversation> getConversations(int datasetId, boolean lazy)
	{
		List<Conversation> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();
		Dataset dataset = (Dataset) session.get(Dataset.class, datasetId);
		session.getTransaction().commit();

		return getConversations(dataset, lazy);
	}

	/**
	 * Returns list of all Conversation database records sorted by daasetId
	 */
	public List<Conversation> getConversations()
	{
		List<Conversation> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			list = session.createQuery("FROM Conversation ORDER BY ConversationId ").list();
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}

	/**
	 * Returns list of all Conversation database records sorted by conversationId
	 */
	public List<Conversation> getConversations(Dataset dataset, ConversationLabel conversationLabel)
	{
		List<Conversation> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			list = (List<Conversation>)
			session.createQuery("FROM Conversation WHERE " +
					" dataset = :dataset " +
			" AND conversationLabel = :conversationLabel")
			.setEntity("dataset", dataset)
			.setEntity("conversationLabel", conversationLabel);
			
			for (Conversation conversation: list )
			{
				Hibernate.initialize(conversation.getMessages());
				Hibernate.initialize(conversation.getAnnotators());
				for (User annotator: conversation.getAnnotators())
					Hibernate.initialize(annotator);
			}
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}

	/**
	 * Returns list of all Conversation database records sorted by conversationId
	 */
	public List<Conversation> getConversations(int datasetId, int conversationLabelId)
	{
		List<Conversation> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			list = session.createQuery("FROM Conversation WHERE " +
					" datasetId = :datasetId " +
			" AND conversationLabelId = :conversationLabelId")
			.setInteger("datasetId", datasetId)
			.setInteger("conversationLabelId", conversationLabelId)
			.list();
			for (Conversation conversation: list )
			{
				Hibernate.initialize(conversation.getMessages());
				Hibernate.initialize(conversation.getAnnotators());
				for (User annotator: conversation.getAnnotators())
					Hibernate.initialize(annotator);
			}
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}


	public Conversation getPreviousConversation(Conversation conversation)
	{
		Conversation previous = null;

		String queryString = 
			"FROM Conversation c1" +
			" WHERE c1.conversationId = " +
			" (SELECT max(conversationId) FROM Conversation c2 " +
			" where c2.dataset.datasetId = ? and c2.conversationId < ?)";

		previous = getConversation(queryString, conversation.getDataset().getDatasetId(), conversation.getConversationId());

		if (previous == null) {
			queryString = 
				"FROM Conversation c1" +
				" WHERE c1.conversationId = " +
				" (SELECT max(conversationId) FROM Conversation c2 " +
				" where c2.dataset.datasetId = ? and c2.conversationId >= ?)";

			previous = getConversation(queryString, conversation.getDataset().getDatasetId(), conversation.getConversationId());				    
		}

		return previous;

	}

	public Conversation getPreviousConversation(Dataset dataset, Conversation conversation)
	{
		Conversation previous;
		final int datasetId = dataset.getDatasetId();
		final int conversationId = conversation.getConversationId();

		String queryString = 
			"FROM Conversation c1" +
			" WHERE c1.conversationId = " +
			" (SELECT max(conversationId) FROM Conversation c2 " +
			" where c2.dataset.datasetId = ? and c2.conversationId < ?)";

		previous = getConversation(queryString, datasetId, conversationId);

		if (previous == null) {
			queryString = 
				"FROM Conversation c1" +
				" WHERE c1.conversationId = " +
				" (SELECT max(conversationId) FROM Conversation c2 " +
				" where c2.dataset.datasetId = ? and c2.conversationId >= ?)";

			previous = getConversation(queryString, datasetId, conversationId);				    
		}

		return previous;

	}

	public Conversation getNextConversation(
			Conversation conversation)
	{
		Conversation next;
		int datasetId = conversation.getDataset().getDatasetId();
		int conversationId = conversation.getConversationId();

		String queryString = 
			"FROM Conversation c1" +
			" WHERE c1.conversationId = " +
			" (SELECT min(conversationId) FROM Conversation c2 " +
			" where c2.dataset.datasetId = ? and c2.conversationId > ?)";

		next = getConversation(queryString, datasetId, conversationId);

		if (next == null) {
			queryString = 
				"FROM Conversation c1" +
				" WHERE c1.conversationId = " +
				" (SELECT min(conversationId) FROM Conversation c2 " +
				" where c2.dataset.datasetId = ? and c2.conversationId <= ?)";

			next = getConversation(queryString, datasetId, conversationId);				    
		}

		return next;
	}


	public Conversation getNextConversation0(
			Conversation conversation)
	{
		Conversation next;
		int datasetId = conversation.getDataset().getDatasetId();
		int conversationId = conversation.getConversationId();

		String queryString = 
			"FROM Conversation c1" +
			" WHERE c1.conversationId = " +
			" (SELECT min(conversationId) FROM Conversation c2 " +
			" where c2.dataset.datasetId = ? and c2.conversationId > ?)";

		next = getConversation(queryString, datasetId, conversationId);

		if (next == null) {
			queryString = 
				"FROM Conversation c1" +
				" WHERE c1.conversationId = " +
				" (SELECT min(conversationId) FROM Conversation c2 " +
				" where c2.dataset.datasetId = ? and c2.conversationId <= ?)";

			next = getConversation(queryString, datasetId, conversationId);				    
		}

		return next;
	}

	/*
	 * Returns the previous conversation with the same conversation label
	 */
	public Conversation getPreviousConversationByConversationLabel(	    
			Conversation conversation
	)
	{
		final int datasetId = conversation.getDataset().getDatasetId();
		final int conversationId = conversation.getConversationId();
		final int conversationLabelId = conversation.getConversationLabel().getConversationLabelId();

		Conversation previous;

		String queryString = "FROM Conversation c1" +
		" WHERE c1.conversationId = " +
		" (SELECT max(conversationId) FROM Conversation c2 " +
		" where c2.dataset.datasetId = ? and c2.conversationId < ? and conversationLabelId = ?)";
		previous = getConversation(queryString, datasetId, conversationId, conversationLabelId);

		// If there is no previous one, go back to the end
		//
		if (previous == null) {
			queryString =     "FROM Conversation c1" +
			" WHERE c1.conversationId = " +
			" (SELECT max(conversationId) FROM Conversation c2 " +
			" where c2.dataset.datasetId = ? and c2.conversationId >= ? and conversationLabelId = ?)";
			previous = getConversation(queryString, datasetId, conversationId, conversationLabelId);
		}
		return previous;
	}

	public Conversation getNextConversationByConversationLabel(	    
			Conversation conversation
	)      
	{
		final int datasetId = conversation.getDataset().getDatasetId();
		final int conversationId = conversation.getConversationId();
		final int conversationLabelId = conversation.getConversationLabel().getConversationLabelId();

		Conversation next = null;
		String queryString =     "FROM Conversation c1" +
		" WHERE c1.conversationId = " +
		" (SELECT min(conversationId) FROM Conversation c2 " +
		" where c2.dataset.datasetId = ? and c2.conversationId > ? and conversationLabelId = ?)";

		next = getConversation(queryString, datasetId, conversationId, conversationLabelId);

		// If there is no next one, go back to the beginning
		//
		if (next == null) {
			queryString =     "FROM Conversation c1" +
			" WHERE c1.conversationId = " +
			" (SELECT min(conversationId) FROM Conversation c2 " +
			" where c2.dataset.datasetId = ? and c2.conversationId <= ? and conversationLabelId = ?)";
			next = getConversation(queryString, datasetId, conversationId, conversationLabelId);
		}
		return next;
	}

	public Conversation getConversation(
			String queryString,
			int datasetId,
			int conversationId
	)      
	{
		Conversation conversation = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			conversation = (Conversation) session.createQuery(queryString)
			.setInteger(0, datasetId)
			.setInteger(1, conversationId)
			.uniqueResult();
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return conversation;
	}


	public Conversation getConversation(
			String queryString,
			int datasetId,
			int conversationId,
			int conversationLabelId
	)      
	{
		Conversation conversation = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			conversation = (Conversation) session.createQuery(queryString)
			.setInteger(0, datasetId)
			.setInteger(1, conversationId)
			.setInteger(2, conversationLabelId)
			.uniqueResult();
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return conversation;
	}


	public Conversation getConversation(int conversationId)
	{
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		Conversation conversation = (Conversation) session.get(Conversation.class, conversationId);
		
		// Forcing initializing the collections
		//
		conversation.getMessages().size();
		conversation.getAnnotators().size();
		
		return conversation; 
	}

	/**
	 * Saves a Conversation object.
	 */
	public void saveConversation(Conversation conversation)
	{
		Session session = HibernateUtil.getSessionFactory()
		.getCurrentSession();
		session.beginTransaction();
		try
		{
			session.saveOrUpdate(conversation);
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
	}

	/**
	 * Deletes Conversation record with matching conversationId 
	 */
	public void deleteConversation(int conversationId)
	{
		Session session = 
			HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();	
		try
		{
			session.delete(session.load(Conversation.class,new Integer(conversationId)));         	    			
			session.flush();
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
	}
}
